package com.gitee.wsl.coroutines.job.trigger

import com.gitee.wsl.coroutines.job.trigger.impl.SimpleTrigger
import com.gitee.wsl.time.MILLIS_PER_HOUR
import com.gitee.wsl.time.MILLIS_PER_MINUTE
import com.gitee.wsl.time.MILLIS_PER_SECOND

/**
 * @author Terracotta
 * @param <T>
 * Trigger class
</T> */
interface IScheduleBuilder<T : IMutableTrigger> {

    fun build(): T
}


/**
 * `SimpleScheduleBuilder` is a [IScheduleBuilder] that defines
 * strict/literal interval-based schedules for `Trigger`s.
 *
 *
 * Quartz provides a builder-style API for constructing scheduling-related
 * entities via a Domain-Specific Language (DSL). The DSL can best be utilized
 * through the usage of static imports of the methods on the classes
 * `TriggerBuilder`, `JobBuilder`,
 * `DateBuilder`, `JobKey`, `TriggerKey` and
 * the various `ScheduleBuilder` implementations.
 *
 *
 *
 * Client code can then use the DSL to write code such as this:
 *
 *
 * <pre>
 * JobDetail job = newJob (MyJob.class).withIdentity ("myJob").build ();
 * Trigger trigger = newTrigger ().withIdentity (triggerKey ("myTrigger", "myTriggerGroup"))
 * .withSchedule (simpleSchedule ().withIntervalInHours (1).repeatForever ())
 * .startAt (futureDate (10, MINUTES))
 * .build ();
 * scheduler.scheduleJob (job, trigger);
</pre> *
 *
 * @see ISimpleTrigger
 *
 * @see CalendarIntervalScheduleBuilder
 *
 * @see CronScheduleBuilder
 *
 * @see IScheduleBuilder
 *
 * @see TriggerBuilder
 */
class SimpleScheduleBuilder protected constructor() : IScheduleBuilder<SimpleTrigger> {
    private var m_nInterval: Long = 0
    private var m_nRepeatCount = 0
    private var m_eMisfireInstruction: ITrigger.EMisfireInstruction =
        ITrigger.EMisfireInstruction.MISFIRE_INSTRUCTION_SMART_POLICY

    /**
     * Build the actual Trigger -- NOT intended to be invoked by end users, but
     * will rather be invoked by a TriggerBuilder which this ScheduleBuilder is
     * given to.
     *
     * @see TriggerBuilder.withSchedule
     */
    override fun build(): SimpleTrigger {
        val ret = SimpleTrigger()
        ret.repeatInterval = m_nInterval
        ret.repeatCount = m_nRepeatCount
        ret.misfireInstruction = m_eMisfireInstruction
        return ret
    }

    /**
     * Specify a repeat interval in milliseconds.
     *
     * @param nIntervalInMillis
     * the number of seconds at which the trigger should repeat.
     * @return the updated SimpleScheduleBuilder
     * @see ISimpleTrigger.getRepeatInterval
     * @see .withRepeatCount
     */

    fun withIntervalInMilliseconds(nIntervalInMillis: Long): SimpleScheduleBuilder {
        m_nInterval = nIntervalInMillis
        return this
    }

    /**
     * Specify a repeat interval in seconds - which will then be multiplied by
     * 1000 to produce milliseconds.
     *
     * @param nIntervalInSeconds
     * the number of seconds at which the trigger should repeat.
     * @return the updated SimpleScheduleBuilder
     * @see ISimpleTrigger.getRepeatInterval
     * @see .withRepeatCount
     */

    fun withIntervalInSeconds(nIntervalInSeconds: Int): SimpleScheduleBuilder {
        m_nInterval = (nIntervalInSeconds * MILLIS_PER_SECOND).toLong()
        return this
    }

    /**
     * Specify a repeat interval in minutes - which will then be multiplied by 60
     * * 1000 to produce milliseconds.
     *
     * @param nIntervalInMinutes
     * the number of seconds at which the trigger should repeat.
     * @return the updated SimpleScheduleBuilder
     * @see ISimpleTrigger.getRepeatInterval
     * @see .withRepeatCount
     */

    fun withIntervalInMinutes(nIntervalInMinutes: Int): SimpleScheduleBuilder {
        m_nInterval = (nIntervalInMinutes * MILLIS_PER_MINUTE).toLong()
        return this
    }

    /**
     * Specify a repeat interval in minutes - which will then be multiplied by 60
     * * 60 * 1000 to produce milliseconds.
     *
     * @param intervalInHours
     * the number of seconds at which the trigger should repeat.
     * @return the updated SimpleScheduleBuilder
     * @see ISimpleTrigger.getRepeatInterval
     * @see .withRepeatCount
     */

    fun withIntervalInHours(intervalInHours: Int): SimpleScheduleBuilder {
        m_nInterval = (intervalInHours * MILLIS_PER_HOUR).toLong()
        return this
    }

    /**
     * Specify a the number of time the trigger will repeat - total number of
     * firings will be this number + 1.
     *
     * @param triggerRepeatCount
     * the number of seconds at which the trigger should repeat.
     * @return the updated SimpleScheduleBuilder
     * @see ISimpleTrigger.getRepeatCount
     * @see .repeatForever
     */

    fun withRepeatCount(triggerRepeatCount: Int): SimpleScheduleBuilder {
        m_nRepeatCount = triggerRepeatCount
        return this
    }

    /**
     * Specify that the trigger will repeat indefinitely.
     *
     * @return the updated SimpleScheduleBuilder
     * @see ISimpleTrigger.getRepeatCount
     * @see ISimpleTrigger.REPEAT_INDEFINITELY
     *
     * @see .withIntervalInMilliseconds
     * @see .withIntervalInSeconds
     * @see .withIntervalInMinutes
     * @see .withIntervalInHours
     */

    fun repeatForever(): SimpleScheduleBuilder {
        m_nRepeatCount = ISimpleTrigger.REPEAT_INDEFINITELY
        return this
    }

    /**
     * If the Trigger misfires, use the
     * [EMisfireInstruction.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY]
     * instruction.
     *
     * @return the updated CronScheduleBuilder
     * @see EMisfireInstruction.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
     */

    fun withMisfireHandlingInstructionIgnoreMisfires(): SimpleScheduleBuilder {
        m_eMisfireInstruction =
            ITrigger.EMisfireInstruction.MISFIRE_INSTRUCTION_IGNORE_MISFIRE_POLICY
        return this
    }

    /**
     * If the Trigger misfires, use the
     * [EMisfireInstruction.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW] instruction.
     *
     * @return the updated SimpleScheduleBuilder
     * @see EMisfireInstruction.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
     */

    fun withMisfireHandlingInstructionFireNow(): SimpleScheduleBuilder {
        m_eMisfireInstruction = ITrigger.EMisfireInstruction.MISFIRE_INSTRUCTION_FIRE_ONCE_NOW
        return this
    }

    /**
     * If the Trigger misfires, use the
     * [EMisfireInstruction.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT]
     * instruction.
     *
     * @return the updated SimpleScheduleBuilder
     * @see EMisfireInstruction.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT
     */

    fun withMisfireHandlingInstructionNextWithExistingCount(): SimpleScheduleBuilder {
        m_eMisfireInstruction =
            ITrigger.EMisfireInstruction.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT
        return this
    }

    /**
     * If the Trigger misfires, use the
     * [EMisfireInstruction.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT]
     * instruction.
     *
     * @return the updated SimpleScheduleBuilder
     * @see EMisfireInstruction.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
     */

    fun withMisfireHandlingInstructionNextWithRemainingCount(): SimpleScheduleBuilder {
        m_eMisfireInstruction =
            ITrigger.EMisfireInstruction.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT
        return this
    }

    /**
     * If the Trigger misfires, use the
     * [EMisfireInstruction.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT]
     * instruction.
     *
     * @return the updated SimpleScheduleBuilder
     * @see EMisfireInstruction.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
     */

    fun withMisfireHandlingInstructionNowWithExistingCount(): SimpleScheduleBuilder {
        m_eMisfireInstruction =
            ITrigger.EMisfireInstruction.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT
        return this
    }

    /**
     * If the Trigger misfires, use the
     * [EMisfireInstruction.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT]
     * instruction.
     *
     * @return the updated SimpleScheduleBuilder
     * @see EMisfireInstruction.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
     */

    fun withMisfireHandlingInstructionNowWithRemainingCount(): SimpleScheduleBuilder {
        m_eMisfireInstruction =
            ITrigger.EMisfireInstruction.MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT
        return this
    }

    companion object {
        /**
         * Create a SimpleScheduleBuilder.
         *
         * @return the new SimpleScheduleBuilder
         */

        fun simpleSchedule(): SimpleScheduleBuilder {
            return SimpleScheduleBuilder()
        }

        /**
         * Create a SimpleScheduleBuilder set to repeat forever with a 1 minute
         * interval.
         *
         * @return the new SimpleScheduleBuilder
         */

        fun repeatMinutelyForever(): SimpleScheduleBuilder {
            return repeatMinutelyForever(1)
        }

        /**
         * Create a SimpleScheduleBuilder set to repeat forever with an interval of
         * the given number of minutes.
         *
         * @return the new SimpleScheduleBuilder
         */

        fun repeatMinutelyForever(minutes: Int): SimpleScheduleBuilder {
            return simpleSchedule().withIntervalInMinutes(minutes).repeatForever()
        }

        /**
         * Create a SimpleScheduleBuilder set to repeat forever with a 1 second
         * interval.
         *
         * @return the new SimpleScheduleBuilder
         */

        fun repeatSecondlyForever(): SimpleScheduleBuilder {
            return repeatSecondlyForever(1)
        }

        /**
         * Create a SimpleScheduleBuilder set to repeat forever with an interval of
         * the given number of seconds.
         *
         * @return the new SimpleScheduleBuilder
         */

        fun repeatSecondlyForever(seconds: Int): SimpleScheduleBuilder {
            return simpleSchedule().withIntervalInSeconds(seconds).repeatForever()
        }

        /**
         * Create a SimpleScheduleBuilder set to repeat forever with a 1 hour
         * interval.
         *
         * @return the new SimpleScheduleBuilder
         */

        fun repeatHourlyForever(): SimpleScheduleBuilder {
            return repeatHourlyForever(1)
        }

        /**
         * Create a SimpleScheduleBuilder set to repeat forever with an interval of
         * the given number of hours.
         *
         * @return the new SimpleScheduleBuilder
         */

        fun repeatHourlyForever(nHours: Int): SimpleScheduleBuilder {
            return simpleSchedule().withIntervalInHours(nHours).repeatForever()
        }

        /**
         * Create a SimpleScheduleBuilder set to repeat the given number of times - 1
         * with a 1 minute interval.
         *
         *
         * Note: Total count = 1 (at start time) + repeat count
         *
         *
         * @return the new SimpleScheduleBuilder
         */

        fun repeatMinutelyForTotalCount(nCount: Int): SimpleScheduleBuilder {
            return repeatMinutelyForTotalCount(nCount, 1)
        }

        /**
         * Create a SimpleScheduleBuilder set to repeat the given number of times - 1
         * with an interval of the given number of minutes.
         *
         *
         * Note: Total count = 1 (at start time) + repeat count
         *
         *
         * @return the new SimpleScheduleBuilder
         */

        fun repeatMinutelyForTotalCount(nCount: Int, nMinutes: Int): SimpleScheduleBuilder {
            require(nCount>0) { "Count" }
            return simpleSchedule().withIntervalInMinutes(nMinutes).withRepeatCount(nCount - 1)
        }

        /**
         * Create a SimpleScheduleBuilder set to repeat the given number of times - 1
         * with a 1 second interval.
         *
         *
         * Note: Total count = 1 (at start time) + repeat count
         *
         *
         * @return the new SimpleScheduleBuilder
         */

        fun repeatSecondlyForTotalCount(nCount: Int): SimpleScheduleBuilder {
            return repeatSecondlyForTotalCount(nCount, 1)
        }

        /**
         * Create a SimpleScheduleBuilder set to repeat the given number of times - 1
         * with an interval of the given number of seconds.
         *
         *
         * Note: Total count = 1 (at start time) + repeat count
         *
         *
         * @return the new SimpleScheduleBuilder
         */

        fun repeatSecondlyForTotalCount(nCount: Int, nSeconds: Int): SimpleScheduleBuilder {
            require(nCount>0) { "Count" }
            return simpleSchedule().withIntervalInSeconds(nSeconds).withRepeatCount(nCount - 1)
        }

        /**
         * Create a SimpleScheduleBuilder set to repeat the given number of times - 1
         * with a 1 hour interval.
         *
         *
         * Note: Total count = 1 (at start time) + repeat count
         *
         *
         * @return the new SimpleScheduleBuilder
         */

        fun repeatHourlyForTotalCount(nCount: Int): SimpleScheduleBuilder {
            return repeatHourlyForTotalCount(nCount, 1)
        }

        /**
         * Create a SimpleScheduleBuilder set to repeat the given number of times - 1
         * with an interval of the given number of hours.
         *
         *
         * Note: Total count = 1 (at start time) + repeat count
         *
         *
         * @return the new SimpleScheduleBuilder
         */

        fun repeatHourlyForTotalCount(nCount: Int, nHours: Int): SimpleScheduleBuilder {
            require(nCount>0) { "Count" }
            return simpleSchedule().withIntervalInHours(nHours).withRepeatCount(nCount - 1)
        }
    }
}